package com.sc.nft.service.impl;

import com.sc.nft.dao.MallUserWalletDao;
import com.sc.nft.entity.minimall.MallUserWallet;
import com.sc.nft.enums.MallUserWalletDetailTypeEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.MallUserWalletDetailService;
import com.sc.nft.service.MallUserWalletService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 商城用户钱包 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-05-20
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallUserWalletServiceImpl implements MallUserWalletService {

    private final MallUserWalletDetailService mallUserWalletDetailService;
    private final MallUserWalletDao mallUserWalletDao;
    private final Redisson redisson;

    /**
     * 获取商城用户钱包
     *
     * @param miniUserId
     * @return
     */
    @Override
    public MallUserWallet getMallUserWallet(Long miniUserId) {
        return mallUserWalletDao.getByMiniUserId(miniUserId);
    }

    /**
     * 添加收入
     *
     * @param mallUserWallet
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRevenue(MallUserWallet mallUserWallet, BigDecimal amount, MallUserWalletDetailTypeEnum mallUserWalletDetailTypeEnum) {
        RLock lock = redisson.getLock(RedisKeyEnum.MALL_USER_WALLET_LOCK.getKey() + mallUserWallet.getId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                log.info("用户钱包Id:{}添加商城用户钱包余额:{}" + mallUserWallet.getId() + amount);
                // 添加收入
                mallUserWalletDao.addRevenue(mallUserWallet.getId(), amount);
                // 添加钱包明细
                mallUserWalletDetailService.addWalletDetail(mallUserWallet.getId(), mallUserWallet.getMiniUserId(),
                        mallUserWalletDetailTypeEnum, amount, BigDecimal.ZERO, amount, mallUserWallet.getBalance(), mallUserWallet.getBalance().add(amount), true);
            } else {
                throw new GlobalRunTimeException("操作用户钱包锁获取失败");
            }
        } catch (Exception e) {
            log.error("添加商城用户钱包余额:{}", mallUserWallet, e);
            throw new GlobalRunTimeException("服务繁忙，请稍后再试！");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 添加提现金额(用户申请提现)
     *
     * @param mallUserWallet
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addWithdrawingAmount(MallUserWallet mallUserWallet, BigDecimal amount, MallUserWalletDetailTypeEnum mallUserWalletDetailTypeEnum) {
        Long walletDetailId = null;
        RLock lock = redisson.getLock(RedisKeyEnum.MALL_USER_WALLET_LOCK.getKey() + mallUserWallet.getId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                log.info("用户钱包Id:{}添加提现金额:{}" + mallUserWallet.getId() + amount);
                // 添加提现金额
                mallUserWalletDao.addWithdrawingAmount(mallUserWallet.getId(), amount);
                // 添加钱包明细
                walletDetailId =  mallUserWalletDetailService.addWalletDetail(mallUserWallet.getId(), mallUserWallet.getMiniUserId(),
                        mallUserWalletDetailTypeEnum, amount, BigDecimal.ZERO, amount, mallUserWallet.getBalance(), mallUserWallet.getBalance().subtract(amount), false);
            } else {
                throw new GlobalRunTimeException("操作用户钱包锁获取失败");
            }
        } catch (Exception e) {
            log.error("添加提现金额:{}", mallUserWallet, e);
            throw new GlobalRunTimeException("服务繁忙，请稍后再试！");
        } finally {
            lock.unlock();
        }
        return walletDetailId;
    }

    /**
     * 提现成功
     *
     * @param mallUserWallet
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSumWithdraw(MallUserWallet mallUserWallet, BigDecimal amount) {
        RLock lock = redisson.getLock(RedisKeyEnum.MALL_USER_WALLET_LOCK.getKey() + mallUserWallet.getId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                log.info("用户钱包Id:{}添加提现金额:{}" + mallUserWallet.getId() + amount);
                // 提现成功
                mallUserWalletDao.addSumWithdraw(mallUserWallet.getId(), amount);
            } else {
                throw new GlobalRunTimeException("操作用户钱包锁获取失败");
            }
        } catch (Exception e) {
            log.error("添加提现金额:{}", mallUserWallet, e);
            throw new GlobalRunTimeException("服务繁忙，请稍后再试！");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 提现失败
     *
     * @param mallUserWallet
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void subWithdrawingAmount(MallUserWallet mallUserWallet, BigDecimal amount, MallUserWalletDetailTypeEnum mallUserWalletDetailTypeEnum) {
        RLock lock = redisson.getLock(RedisKeyEnum.MALL_USER_WALLET_LOCK.getKey() + mallUserWallet.getId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                log.info("用户钱包Id:{}添加提现金额:{}" + mallUserWallet.getId() + amount);
                // 添加提现金额
                mallUserWalletDao.subWithdrawingAmount(mallUserWallet.getId(), amount);
                // 添加钱包明细
                mallUserWalletDetailService.addWalletDetail(mallUserWallet.getId(), mallUserWallet.getMiniUserId(),
                        mallUserWalletDetailTypeEnum, amount, BigDecimal.ZERO, amount, mallUserWallet.getBalance(), mallUserWallet.getBalance().add(amount), true);
            } else {
                throw new GlobalRunTimeException("操作用户钱包锁获取失败");
            }
        } catch (Exception e) {
            log.error("添加提现金额:{}", mallUserWallet, e);
            throw new GlobalRunTimeException("服务繁忙，请稍后再试！");
        } finally {
            lock.unlock();
        }
    }


    /**
     * 用户注册初始化钱包
     *
     * @param miniUserId
     * @return
     */
    @Override
    public boolean initWallet(Long miniUserId) {
        MallUserWallet mallUserWallet = mallUserWalletDao.getByMiniUserId(miniUserId);
        if (Objects.isNull(mallUserWallet)) {
            MallUserWallet saveMallUserWallet = new MallUserWallet();
            saveMallUserWallet.setMiniUserId(miniUserId);
            saveMallUserWallet.setSumIncome(BigDecimal.ZERO);
            saveMallUserWallet.setBalance(BigDecimal.ZERO);
            saveMallUserWallet.setWithdrawingAmount(BigDecimal.ZERO);
            saveMallUserWallet.setSumWithdraw(BigDecimal.ZERO);
            saveMallUserWallet.insert();
        }
        return true;
    }
}
